﻿#include <iostream>
#include "PrintV.h"


int g_x{ 5 };

int main()
{
	std::cout << "Hello World!\n";

	/*C++支持以下复合类型：
		函数
		数组（Arrays）
		指针类型：
		对象指针
		函数指针
		指向成员类型的指针：
		指向成员数据的指针
		指向成员函数的指针
		引用类型：
		左值引用
		右值引用
		枚举类型：
		强作用域枚举
		弱作用域枚举
		类类型：
		struct
		class
		union*/

	int x{ 4 };
	//与号不是“地址”，而是“左值引用”。
	int* at = &x;
	std::cout << "指针地址：" << at << "\n";

	// ref 现在是 x 的别名
	int& ref = x;
	std::cout << "ref：" << ref << "\n";

	x = 5;
	std::cout << "ref：" << ref << "\n";

	ref = 6;
	std::cout << "ref：" << ref << "\n";

	//一旦初始化,C++中的引用就不能重置，这意味着不能将其更改为引用另一个对象。
	int y = 7;
	//上面这一行不会将ref的引用重置为y,仅仅使用Y的值而不是引用
	ref = y;
	std::cout << "ref：" << ref << "\n";


	/*
	由于ref1是对var的引用，因此在表达式（如初始值设定项）中使用时，
	ref1的计算结果为var.因此ref2只是一个普通的左值引用（如其类型int& 所示），
	绑定到var。
	对引用（到int）的引用将具有语法int&& –但由于C++不支持对引用的引用
	*/
	int var{};
	int& ref1{ var };  // 绑定到var的左值引用
	int& ref2{ ref1 }; // 绑定到var的左值引用


	const int y2{ 22 };
	/*通过在声明左值引用时使用const关键字，我们告诉左值引用将其引用的对象视为const。
	这样的引用称为对常量值的左值引用*/
	const int& refy{ y2 };
	std::cout << "refy：" << refy << "\n";
	//可以引用但是不能通过引用修改值
	//refy = 12;


	int y3{ 33 };
	//静态引用非静态变量，但是不能通过引用变量改变原值
	const int& refy2{ y3 };
	//但是不能通过引用变量改变原值
	//refy2 = 2;

	//当这种情况发生时，将创建一个临时对象并用右值初始化，
	// 并且将常量引用绑定到该临时对象。
	const int& ref3{ 5 }; // okay: 5 是一个 右值

	//为了避免在这种情况下出现悬空引用，C++有一个特殊的规则：
	// 当常量值引用直接绑定到临时对象时，
	// 临时对象的生命周期将被扩展以匹配引用的生命周期。



	/*constexpr引用无法绑定到（非静态）局部变量。这是因为在实际调用
    定义局部变量的函数之前，局部变量的地址是未知的。*/
	constexpr int& ref4{ g_x }; // ok, 可以绑定到全局变量

	static int s_x{ 6 };
	constexpr int& ref5{ s_x }; // ok, 可以绑定到静态局部变量




	//引用的应用场景： 函数参数的传递，使用引用的好处是减少了对象的复制成本	
	std::string s = "hello world cat";
	//通过引用，我们可以将原始对象的别名传递给函数，而无需在每次调用函数时复制它。
	print(s);


	//修改副本与引用的区别演示
	std::cout << "修改副本前 y=：" << y << "\n";
	addOne(y); //y的值不会有变化，实际修改的是副本，原类型不会改变
	std::cout << "修改副本后 y=：" << y << "\n";


	std::cout << "修改引用前 y=：" << y << "\n";
	addOne2(y); //y的值已经变化，因为修改引用相当于修改源对象
	std::cout << "修改引用后 y=：" << y << "\n";

	std::string_view ss = "gjhsdfihgsoidhgksjdfngjsdfhgsknsjg";
	print(ss);


}
